package client;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.Semaphore;

import file.*;
import utils.*;

public class Client extends Observable implements Observer {
	
	public Semaphore _SEMAPHORE_NB_CONNECTION_;
	private String ip;
	private int port;
	private ArrayList<File> mySeed;
	private Leech myLeech;
	public final ClientConfiguration clientConfig;
	private ArrayList<ConnectedPeer> _peersImConnectedTo;

	public Client(ClientConfiguration client){
		this.clientConfig = client;
		this.ip = client.getIpClient();
		this.port = client.getPortClient();
		_SEMAPHORE_NB_CONNECTION_ = new Semaphore((int) this.clientConfig.getNbConnectionMax());
		try {
			this.mySeed = SharedFiles.getSharedFileFromFolder(this.clientConfig.getSeedPath(), this.clientConfig.getHashEncryption(), this.clientConfig.getPiecesSize(), true);
			this.myLeech = new Leech();
			this.myLeech.addObserver(this);
			this.myLeech.setMyLeech(SharedFiles.getSharedFileFromFolder("leech", this.clientConfig.getHashEncryption(), this.clientConfig.getPiecesSize(), false));
			_peersImConnectedTo = new ArrayList<ConnectedPeer>();
			this.initFilesObservers();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * Ajoute un observateur par fichier leeché
	 */
	private void initFilesObservers(){
		for(File f : this.myLeech.getMyLeech()){
			f.addObserver(this);
		}
	}

	/**
	 * @return the ip
	 */
	public String getIp() {
		return ip;
	}

	/**
	 * @param ip the ip to set
	 */
	public void setIp(String ip) {
		this.ip = ip;
	}

	/**
	 * @return the port
	 */
	public int getPort() {
		return port;
	}

	/**
	 * @param port the port to set
	 */
	public void setPort(int port) {
		this.port = port;
	}

	
	/**
	 * @return the mySeed
	 */
	public ArrayList<File> getMySeed() {
		return mySeed;
	}

	/**
	 * @param mySeed the mySeed to set
	 */
	public void setMySeed(ArrayList<File> mySeed) {
		this.mySeed = mySeed;
	}

	/**
	 * @return the myLeech
	 */
	public ArrayList<File> getMyLeech() {
		return myLeech.getMyLeech();
	}
	
	public Leech getMyLeechObservable(){
		return myLeech;
	}

	/**
	 * @param myLeech the myLeech to set
	 */
	public void setMyLeech(ArrayList<File> myLeech) {
		this.myLeech = new Leech(myLeech);
	}
	
	@Override
	public void update(Observable arg0, Object arg1) {
		if (arg1 instanceof ArrayList){
					
			for(int i =0; i< ((ArrayList<File>)arg1).size(); i++){
				try {
					this._SEMAPHORE_NB_CONNECTION_.acquire(((ArrayList<File>)arg1).get(i).getPeers().size());
					ConnectionToPeers cp = new ConnectionToPeers(((ArrayList<File>)arg1).get(i), (int) this.clientConfig.getMaxSizeData(), this.clientConfig.getPeersUpdateTime(), this);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}else if (arg1 instanceof File){
			
			try {
				this._SEMAPHORE_NB_CONNECTION_.acquire(((File)arg1).getPeers().size());
				ConnectionToPeers cp = new ConnectionToPeers((File) arg1, (int) this.clientConfig.getMaxSizeData(), this.clientConfig.getPeersUpdateTime(), this);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public ArrayList<ConnectedPeer> getPeersImConnectedTo(){
		return _peersImConnectedTo;
	}
	
	/**
	 * @return the _peersImConnectedTo
	 */
	public ArrayList<String> getStringPeersImConnectedTo(){
		ArrayList<String> ret = new ArrayList<String>();
		for(int i = 0; i < _peersImConnectedTo.size(); i++){
			if(!_peersImConnectedTo.get(i).getSockToPeer().isClosed()){
				String str = _peersImConnectedTo.get(i).getSockToPeer().getInetAddress().toString() + ":"+ _peersImConnectedTo.get(i).getSockToPeer().getPort();
				ret.add(str);
			}
		}
		return ret;
	}
}